# -*- coding: utf-8 -*-
from PyQt5.QtWidgets import *
from PyQt5 import QtCore, QtGui
from transfer.client import client, ServerFault
from client.qtwidget_helper import *
from client.ui_category import Ui_CategoriesForm
from client.ui_login import Ui_LoginForm
from client.ui_main import Ui_MainForm
from client.ui_message import Ui_MessageForm
from client.ui_readtext import Ui_readForm
from client.ui_send import Ui_sendForm


class CategoriesForm(QWidget):
    """
    基于QtWidgets.QWidget的子类。
    实现了一个消息类别管理界面，用户可以通过界面进行刷新、添加、删除和更新消息类别。
    """
    closed = QtCore.pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)
        self.ui = Ui_CategoriesForm()
        self.ui.setupUi(self)
        self.list_widget = TListWidget(self.ui.listWidget)
        self.on_pushButton_refresh_pressed()

    def on_pushButton_refresh_pressed(self):
        """
        刷新按钮按下时的操作。
        清空列表，获取所有消息类别数据并设置到列表中。
        """
        self.list_widget.clear()
        # 调用服务端服务函数category_get_all()获取所有类别
        tdata = client.remote.category_get_all()
        if tdata:
            self.list_widget.set_db_data(tdata)
            self.ui.lineEdit.clear()

    def on_pushButton_add_pressed(self):
        """
        添加按钮按下时的操作。
        从输入框中获取类别名称，如果存在则添加到数据库中，并刷新界面。
        """
        n = self.ui.lineEdit.text().strip()
        if n:
            try:
                # 调用服务端服务函数category_add_one()添加类别
                client.remote.category_add_one({'name': n})
                self.on_pushButton_refresh_pressed()
            except ServerFault as e:
                if 'UNIQUE constraint failed' in e.faultString:
                    print('类别名已存在，添加失败')
                    QMessageBox.critical(
                        self, '错误',
                        '类别名已存在，添加失败\n%s' % e.faultString)

    def on_pushButton_del_pressed(self):
        """
        删除按钮按下时的操作。
        获取当前选中的类别名称，检查该类别下是否有消息，如果没有则从数据库中删除该类别，并刷新界面。
        """
        if self.list_widget.has_selected():
            name = self.list_widget.get_current_text()
            if name:
                client.remote.category_delete(name)
                self.on_pushButton_refresh_pressed()

    def on_pushButton_update_pressed(self):
        """
        更新按钮按下时的操作。
        获取当前选中的类别名称和新的类别名称，如果新名称存在，则更新数据库中该类别的名称，并刷新界面。
        """
        if self.list_widget.has_selected():
            name = self.list_widget.get_current_text()
            new_name = self.ui.lineEdit.text().strip()
            if name and new_name:
                client.remote.category_update(name, new_name)
                self.on_pushButton_refresh_pressed()

    def closeEvent(self, a0: QtGui.QCloseEvent) -> None:
        """
        关闭窗口时的操作。
        发出关闭信号并接受关闭事件。
        """
        self.closed.emit()
        a0.accept()


class LoginForm(QWidget):
    login_succesed = QtCore.pyqtSignal(dict)
    user_canceled = QtCore.pyqtSignal()
    login_faild = QtCore.pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent=parent)
        self.ui = Ui_LoginForm()
        self.ui.setupUi(self)

        self.login_count = 3

    def on_bt_submit_pressed(self):
        try:
            self.login_count = self.login_count - 1
            if self.login_count < 0:
                QMessageBox.information(self, '提示', "登录次数已达3次，系统退出！")
                self.login_faild.emit()
                self.close()
            name = self.ui.lineEdit_name.text().strip()
            pwd = self.ui.lineEdit_pwd.text().strip()
            # 输入不空并远程验证用户名密码
            if name == '':
                QMessageBox.information(self, '提示', "用户名不能为空！")
                return
            if pwd == '':
                QMessageBox.information(self, '提示', "密码 不能为空！")
                return
            rs = client.login(name, pwd)
            if rs:
                # 登录成功，关闭登录窗口
                self.login_succesed.emit(rs)
                self.close()
            else:
                QMessageBox.information(self, '提示', "用户名或密码错误！")
                # 清空输入

        except Exception as e:
            print(e)
        finally:
            self.ui.lineEdit_name.setText('')
            self.ui.lineEdit_name.setFocus()
            self.ui.lineEdit_pwd.setText('')

    def on_bt_cancel_pressed(self):
        self.user_canceled.emit()
        self.close()

    def keyPressEvent(self, event):
        """
        按下回车键的处理函数
        """
        super(LoginForm, self).keyPressEvent(event)
        if event.key() == QtCore.Qt.Key_Enter or \
                event.key() == QtCore.Qt.Key_Return:
            # print('enter : Enter')
            self.ui.bt_submit.click()


class MainForm(QWidget):

    def __init__(self, parent=None):
        super().__init__(parent=parent)
        self.ui = Ui_MainForm()
        self.ui.setupUi(self)

        # 记录登录用户信息
        self.user_info = None
        # 用于保存登录窗口，所有子窗口的
        self.login_form = None

        self.time_id = 0
        self.refresh_id = 0
        self.all_msg = {}
        self.inbox = TTableWidget(self.ui.inboxtable)
        self.inbox.set_func_item_clicked(self.inbox_clicked)
        self.inbox.set_func_item_double_clicked(self.inbox_double_clicked)
        self.outbox = TTableWidget(self.ui.outboxtable)
        self.outbox.set_func_item_clicked(self.outbox_clicked)

        self.show_login_form()

    def inbox_clicked(self, row, col, text):
        msg = self.inbox.get_row_data(row)
        if msg:
            try:
                fm = self.all_msg[int(msg['fmsg'])]
                if fm['name'] == '自由报文':
                    self.ui.textBrowser.setPlainText(msg['text'])
                else:
                    self.ui.textBrowser.setPlainText(
                        fm['text'].format_map(
                            dict(zip(fm['elementlist'].split('|'), msg['text'].split('|'))))
                    )
                if msg['rstatus'] == '新接收':
                    client.remote.inbox_read(self.user_info['number'], msg['id'])
                    self.inbox.set_cell_data(row, 3, '已阅读')
            except Exception as e:
                print(e)

    def outbox_clicked(self, row, col, text):
        msg = self.outbox.get_row_data(row)
        if msg:
            self.ui.textBrowser_receipt.setPlainText(msg['receipt'])

    def inbox_double_clicked(self, row, col, text):
        msg = self.inbox.get_row_data(row)
        if msg['rstatus'] == '已阅读':
            self.readForm = readForm(msg, self.user_info)
            self.readForm.ui.textBrowser.setPlainText(
                self.ui.textBrowser.toPlainText()
            )
            self.readForm.show()
            self.on_refreshButton_pressed()

    def closeEvent(self, a0: QtGui.QCloseEvent) -> None:
        if self.time_id != 0:
            self.killTimer(self.time_id)
        if self.refresh_id != 0:
            self.killTimer(self.refresh_id)
        return super().closeEvent(a0)

    def show_login_form(self):
        """
        创建并显示登录窗口
        """
        self.login_form = LoginForm(self)
        # 设置窗口类型为窗口
        self.login_form.setWindowFlag(QtCore.Qt.WindowType.Window)
        self.login_form.user_canceled.connect(self.close)
        self.login_form.login_faild.connect(self.close)
        self.login_form.login_succesed.connect(self.initUI)
        self.login_form.show()

    def initUI(self, user_info):
        """
        对主界面进行初始化
        """
        # 记录用户信息
        self.user_info = user_info
        if user_info['role'] == 'admin':
            self.ui.userInfo.setText('欢迎%s\n%s%s' % (
                '管理员', user_info['name'], user_info['rank']))
            self.ui.pushButton_formatMsg.setVisible(True)
        else:
            self.ui.userInfo.setText('欢迎%s\n%s%s' % (
                '用户', user_info['name'], user_info['rank']))
            # 一般用户不能管理格式化消息，将格式化消息管理按钮隐藏
            self.ui.pushButton_formatMsg.setVisible(False)

        self.time_id = self.startTimer(1000)
        self.refresh_id = self.startTimer(10 * 1000)
        for m in client.remote.msg_get_all():
            self.all_msg[m['id']] = m
        self.on_refreshButton_pressed()
        self.show()

    def timerEvent(self, a0: QtCore.QTimerEvent):
        if a0.timerId() == self.time_id:
            import datetime
            self.ui.timeinfor.setText('标准时间：\n %s' %
                                      datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
        if a0.timerId() == self.refresh_id:
            self.auto_refresh()
        super().timerEvent(a0)

    def auto_refresh(self):
        widget = {0: self.inbox, 1: self.outbox}
        active = self.ui.tabWidget.currentIndex()
        msg = widget[active].get_row_data(widget[active].get_current_row())
        has_selected = widget[active].has_selected()
        self.on_refreshButton_pressed()
        if msg and has_selected:
            row = 0
            while row < widget[active].get_row_count():
                if msg['id'] == widget[active].get_row_data(row).get('id', None):
                    break
                row += 1
            widget[active].set_current_cell(row, 0)
            widget[active].item_clicked()

    def on_refreshButton_pressed(self):
        self.inbox.clear()
        self.outbox.clear()
        inbox_data = client.remote.get_inbox(self.user_info['number'])
        if inbox_data:
            self.inbox.set_db_data(inbox_data)
            self.inbox.hide_columns((0, 6))
            n = 0
            for t in inbox_data:
                if t['rstatus'] == '新接收':
                    n += 1
            self.ui.msgshow.setHtml('你有<b>%d</b>条新信息未读' % n)
        outbox_data = client.remote.get_outbox(self.user_info['number'])
        if outbox_data:
            self.outbox.set_db_data(outbox_data)
            self.outbox.hide_columns((0, 6))

    def on_pushButton_formatMsg_pressed(self):
        self.msgform = MessageForm(self)
        self.msgform.setWindowFlag(QtCore.Qt.WindowType.Window)
        self.msgform.setWindowModality(QtCore.Qt.WindowModality.WindowModal)
        self.msgform.show()

    def on_sendButton_pressed(self):
        self.sendForm = sendForm(self.user_info, self)
        self.sendForm.setWindowFlag(QtCore.Qt.WindowType.Window)
        self.sendForm.closed.connect(self.on_refreshButton_pressed)
        self.sendForm.show()

    def on_delButton_pressed(self):
        index = self.ui.tabWidget.currentIndex()
        if index == 0:  # inbox
            cur_row = self.inbox.get_current_row()
            if cur_row >= 0:
                msg = self.inbox.get_row_data(cur_row)
                client.remote.inbox_text_del(self.user_info['number'], msg['id'])

        elif index == 1:  # outbox
            cur_row = self.outbox.get_current_row()
            if cur_row >= 0:
                msg = self.outbox.get_row_data(cur_row)
                client.remote.outbox_text_del(self.user_info['number'], msg['id'])
        self.on_refreshButton_pressed()

    def on_pushButton_exit_pressed(self):
        self.close()


class MessageForm(QWidget):

    def __init__(self, parent=None):
        super().__init__(parent)
        self.ui = Ui_MessageForm()
        self.ui.setupUi(self)
        self.category_form = None
        # 绑定便捷类
        self.msg_tree_widget = TTreeWidget(self.ui.treeWidget)
        # 注册单击处理函数
        self.msg_tree_widget.set_func_item_clicked(self.tree_clicked)
        self.get_format_msg()

    def tree_clicked(self, row, col, name):
        """
        事件处理函数，默认传入参数有三个：
        row：单击（或双击）的行标
        col：单击（或双击）的列标
        name：单击（或双击）的item的text值
        """
        fm = client.remote.msg_get(name)
        print(fm)
        if fm:
            self.ui.lineEdit.setText(name)
            self.ui.textEdit.setPlainText(fm['text'])
            self.ui.comboBox.setCurrentText(fm['category'])
        else:
            self.ui.lineEdit.clear()
            self.ui.textEdit.clear()

    def get_format_msg(self):
        """将格式化消息类别和格式化消息数据按树形控件数据要求进行整理"""
        self.msg_tree_widget.clear()
        self.ui.comboBox.clear()
        self.ui.lineEdit.clear()
        self.ui.textEdit.clear()
        # 设置树形控件头部（顶部）标签
        self.msg_tree_widget.set_header('name')

        tree = []  # 以(id, name, pid)的形式保存数据
        tid = 1
        category_tid = {}  # 用于由category_name->tid的查找

        for c in client.remote.category_get_all():
            self.ui.comboBox.addItem(c['name'])
            tree.append((tid, c['name'], 0))
            category_tid[c['name']] = tid
            tid += 1
        # 按照树形控件数据结构继续添加格式化消息
        for m in client.remote.msg_get_all():
            tree.append((tid, m['name'], category_tid[m['category']]))
            tid += 1
        self.msg_tree_widget.set_data(tree)

    def on_pushButton_category_pressed(self):
        self.category_form = CategoriesForm(self)
        # 设置窗口类型为窗口
        self.category_form.setWindowFlag(QtCore.Qt.WindowType.Window)
        self.category_form.closed.connect(self.get_format_msg)
        self.category_form.show()

    def _get_ui_data(self) -> dict:
        """获取界面输入数据，并按数据库列转化为字典型数据"""
        name = self.ui.lineEdit.text().strip()
        text = self.ui.textEdit.toPlainText()
        category = self.ui.comboBox.currentText()
        if not name or not text or not category:
            return {}

        def _get_elementlist(text: str):
            """提取text中{}内的变量"""
            elementlist = []
            _text = text
            start = _text.find('{')  # 查找第一个{
            end = _text.find('}')  # 查找第一个}
            while 0 <= start <= end and _text:
                # 保存 {}之间的字符串
                elementlist.append(_text[start + 1:end])
                # 在剩下是字符串中继续寻找
                _text = _text[end + 1:]
                start = _text.find('{')
                end = _text.find('}')
            return elementlist

        return {'name': name, 'text': text,
                'elementlist': '|'.join(_get_elementlist(text)),
                'category': category}

    def on_pushButton_add_pressed(self):
        # 获取UI数据
        data = self._get_ui_data()
        if data:
            try:
                client.remote.msg_add_one(data)
                self.get_format_msg()
            except ServerFault as e:
                if 'UNIQUE constraint failed' in e.faultString:
                    print('消息名已存在，添加失败')
                    QMessageBox.critical(
                        self, '错误',
                        '消息名已存在，添加失败\n%s' % e.faultString)

    def on_pushButton_update_pressed(self):
        # 判断是否有选中项
        if self.msg_tree_widget.has_selected():
            # 获取当前选中项的文本
            current = self.msg_tree_widget.get_current_text()
            if current:
                client.remote.msg_update(current, self._get_ui_data())
                self.get_format_msg()

    def on_pushButton_del_pressed(self):
        # 判断是否有选中项
        if self.msg_tree_widget.has_selected():
            # 获取当前选中项的文本
            current = self.msg_tree_widget.get_current_text()
            if current:
                # 删除数据
                client.remote.msg_delete(current)
                # 更新格式化消息
                self.get_format_msg()


class readForm(QWidget):
    closed = QtCore.pyqtSignal()

    def __init__(self, text: dict, usr: dict, parent=None):
        super().__init__(parent=parent)
        self.ui = Ui_readForm()
        self.ui.setupUi(self)
        self.text = text
        self.user = usr

    def on_pushButton_pressed(self):
        r = self.ui.plainTextEdit.toPlainText()
        if r:
            client.remote.inbox_receipt(
                self.user['number'],
                self.text['id'], r)
            QMessageBox.information(self, '提示', '回执成功！')
            self.close()
        else:
            QMessageBox.critical(self, '提示', '请输入回执内容！')

    def closeEvent(self, a0: QtGui.QCloseEvent) -> None:
        self.closed.emit()
        return super().closeEvent(a0)


class sendForm(QWidget):
    closed = QtCore.pyqtSignal()

    def __init__(self, usr, parent=None):
        super().__init__(parent=parent)
        self.ui = Ui_sendForm()
        self.ui.setupUi(self)

        self.user = usr
        self.msg_id = []  # 树形结构id
        self.all_msg = {}
        self.msg_tree = TTreeWidget(self.ui.formattedmsgtree)
        self.msg_tree.set_func_item_double_clicked(
            self.msg_tree_double_clicked)

        self.all_user = []
        self.user_tree = TTreeWidget(self.ui.usertree)
        self.user_tree.set_func_item_double_clicked(
            self.user_tree_double_clicked)
        self.get_all_msg()
        self.get_all_user()
        # 设置自由报文为当前选中报文
        self.cur_msg: dict = self.get_msg_by_name('自由报文')

    def get_msg_by_name(self, name):
        fm = {}
        for m in self.all_msg.values():
            if m['name'] == name:
                fm = m
                break
        return fm

    def msg_tree_double_clicked(self, row, col, text):
        cur_item = self.msg_tree.get_current_item()
        if cur_item[0] in self.msg_id:  #
            fm = self.get_msg_by_name(text)
            if fm:
                # 替换格式化消息中的变量名后再设置
                args = fm['elementlist'].split('|')
                self.ui.textEdit.setPlainText(
                    str(fm['text']).format_map(dict(zip(args, ['{}'] * len(args)))))
                self.cur_msg = fm

    def user_tree_double_clicked(self, row, col, text: str):
        usr = text[:text.find('(')]
        if usr in self.all_user:
            re = self.ui.receiverslabel.text().strip()
            if re:
                t = self.ui.receiverslabel.text().split(', ')
                if text in t:
                    t.remove(text)
                else:
                    t.append(text)
                self.ui.receiverslabel.setText(', '.join(t))
            else:
                self.ui.receiverslabel.setText(text)

    def get_all_msg(self):
        self.msg_tree.clear()
        self.msg_tree.set_header('name')

        tree = []  # 以(id, name, pid)的形式保存数据
        tid = 1
        category_tid = {}  # 用于由category_name->tid的查找

        for c in client.remote.category_get_all():
            tree.append((tid, c['name'], 0))
            category_tid[c['name']] = tid
            tid += 1
        # 按照树形控件数据结构继续添加格式化消息
        for m in client.remote.msg_get_all():
            tree.append((tid, m['name'], category_tid[m['category']]))
            self.msg_id.append(tid)
            tid += 1
            self.all_msg[m['id']] = m
        self.msg_tree.set_data(tree)

    def get_all_user(self):
        self.user_tree.clear()
        self.user_tree.set_header('单位')
        dep = client.remote.department_get_all()
        tree = dep[1]
        tid = len(tree) + 1
        # 按照树形控件数据结构继续添加用户信息
        for m in client.remote.user_get_all():
            if m['dep'] is not None:
                tree.append((tid, '%s(%s)' % (m['number'], m['name']), m['dep']))
            else:
                tree.append((tid, '%s(%s)' % (m['number'], m['name']), 0))
            tid += 1
            self.all_user.append(m['number'])
        self.user_tree.set_data(tree)

    @staticmethod
    def _get_elementlist(text: str):
        elementlist = []
        _text = text
        start = _text.find('{')
        end = _text.find('}')
        while 0 <= start <= end and _text:
            elementlist.append(_text[start + 1:end])
            _text = _text[end + 1:]
            start = _text.find('{')
            end = _text.find('}')
        return elementlist

    def on_sendButton_pressed(self):
        rev = self.ui.receiverslabel.text()
        text = self.ui.textEdit.toPlainText()
        if not rev:
            QMessageBox.critical(self, '错误', '请选择发送目标！')
            return
        if not text:
            QMessageBox.critical(self, '错误', '请输入报文内容！')
            return
        if not self.cur_msg:
            QMessageBox.critical(self, '错误', '请选择报文！')
            return
        if self.cur_msg['name'] == '自由报文':
            data = {
                'text': text,
                'receiver': [r[:r.find('(')] for r in rev.split(', ')],
                'sender': self.user['number'],
                'fmsg': self.cur_msg['id']
            }
        else:
            vals = self._get_elementlist(text)
            data = {
                'text': '|'.join(vals),
                'receiver': [r[:r.find('(')] for r in rev.split(', ')],
                'sender': self.user['number'],
                'fmsg': self.cur_msg['id']
            }
        client.remote.send_msg(data)
        QMessageBox.information(self, '提示', '发送成功！')
        self.ui.clearButton.clicked.emit()

    def closeEvent(self, a0: QtGui.QCloseEvent) -> None:
        self.closed.emit()
        return super().closeEvent(a0)
